/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "x509_cert_selector.h"

#include <securec.h>

#include "cf_blob.h"
#include "config.h"
#include "cf_result.h"
#include "cf_log.h"
#include "cf_memory.h"
#include "cf_result.h"
#include "utils.h"
#include "cert_utils_openssl.h"

typedef CfResult (*HcfCertUtilsSpiCreateFunc)(HcfCertUtilsSpi **);

typedef struct {
    HcfX509CertSelector base;
    HcfCertUtilsSpi *spiObj;
} HcfX509CertSelectorImpl;

typedef struct
{
    HcfCertUtilsSpiCreateFunc createFunc;
} HcfCertUtilsFuncSet;

typedef struct
{
    const char *certType;
    HcfCertUtilsFuncSet funcSet;
} HcfCertUtilsFactoryAbility;

static const char *GetX509CertSelectorClass(void)
{
    return "HcfX509CertSelector";
}

static const HcfCertUtilsFactoryAbility X509_CERTIFICATE_ABILITY_SET[] = {
    {"X509", {
                 OpensslCertUtilsSpiCreate,
             }}};

static const HcfCertUtilsFuncSet *FindAbility(const char *certType)
{
    if (certType == NULL)
    {
        LOGE("CertType is null!");
        return NULL;
    }
    for (uint32_t i = 0; i < sizeof(X509_CERTIFICATE_ABILITY_SET) / sizeof(HcfCertUtilsFactoryAbility); i++)
    {
        if (strcmp(X509_CERTIFICATE_ABILITY_SET[i].certType, certType) == 0)
        {
            return &(X509_CERTIFICATE_ABILITY_SET[i].funcSet);
        }
    }
    LOGE("Cert not support! [cert]: %s", certType);
    return NULL;
}

static void DestroyX509CertSelector(CfObjectBase *self)
{
    if (self == NULL)
    {
        LOGE("Invalid input parameter.");
        return;
    }
    if (!IsClassMatch(self, GetX509CertSelectorClass()))
    {
        LOGE("Class is not match.");
        return;
    }
    HcfX509CertSelector *selector = (HcfX509CertSelector *)self;
    CfBlobDataFree(&selector->data->validDate);
    CfBlobDataFree(&selector->data->issuer);
    CfBlobDataFree(&selector->data->keyUsage);
    CfBlobDataFree(&selector->data->nameConstraint);
    CfBlobDataFree(&selector->data->privateKeyValid);
    CfBlobDataFree(&selector->data->serialNumber);
    CfBlobDataFree(&selector->data->subject);
    CfBlobDataFree(&selector->data->subjectKeyIdentifier);
    CfBlobDataFree(&selector->data->publicKey);
    CfBlobDataFree(&selector->data->publicKeyAlgID);
    FreeCfBlobArray(selector->data->extendedKeyUsage.data, selector->data->extendedKeyUsage.count);
    FreeCfBlobArray(selector->data->certPolicy.data, selector->data->certPolicy.count);
    CfFree(selector->data);
    selector->data = NULL;
    CfFree(selector);
}

CfResult HcfX509CertSelectorCreate(HcfX509CertSelector **selector)
{
    CF_LOG_I("enter HcfX509CertSelectorCreate");
    if (selector == NULL)
    {
        return CF_INVALID_PARAMS;
    }
    const HcfCertUtilsFuncSet *funcSet = FindAbility("X509");
    if (funcSet == NULL)
    {
        return CF_NOT_SUPPORT;
    }
    HcfCertUtilsSpi *spiObj = NULL;
    CfResult res = funcSet->createFunc(&spiObj);
    if (res != CF_SUCCESS)
    {
        LOGE("Failed to create spi object!");
        return res;
    }

    HcfX509CertSelectorImpl *ret = (HcfX509CertSelectorImpl *)HcfMalloc(sizeof(HcfX509CertSelectorImpl), 0);
    if (ret == NULL)
    {
        LOGE("Failed to allocate ret memory!");
        return CF_ERR_MALLOC;
    }
    ret->base.base.destroy = DestroyX509CertSelector;
    ret->base.base.getClass = GetX509CertSelectorClass;
    ret->spiObj = spiObj;
    ret->base.data = (HcfX509CertSelectorData *)HcfMalloc(sizeof(HcfX509CertSelectorData), 0);
    if (ret->base.data == NULL)
    {
        LOGE("Failed to allocate ret memory!");
        return CF_ERR_MALLOC;
    }
    ret->base.data->minPathLenConstraint = -1; // default

    *selector = (HcfX509CertSelector*)ret;
    return CF_SUCCESS;
}

CfResult AddSubjectAlternativeNames(HcfX509CertSelector *self, int32_t type, CfBlob name)
{
    return CF_SUCCESS;
}

CfResult match(HcfX509CertSelector *self, HcfX509Certificate *cert, bool *boolRet)
{

    *boolRet = true;
    return CF_SUCCESS;
}
